package com.lili.collection.file.handle;

import cn.hutool.core.text.csv.CsvData;
import cn.hutool.core.text.csv.CsvReader;
import cn.hutool.core.text.csv.CsvRow;
import cn.hutool.core.text.csv.CsvUtil;
import cn.hutool.core.util.ObjectUtil;
import com.lili.collection.core.fields.Field;
import com.lili.collection.core.runner.result.ErrOutputData;
import com.lili.collection.core.utils.DateConvertUtil;
import com.lili.collection.file.base.FileRecordInfo;
import com.lili.collection.file.config.FileInputConfig;
import com.lili.collection.jdbc.utils.JdbcCharUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.map.HashedMap;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
 *描述: 文件读取
 *@date:2023/3/6  14:26
 *@author:lili
 */
@Slf4j
public class FileHandleUtil {

    /**
     * 解析xls,xlsx,csv文件
     * @param wjm 文件名
     * @param fileByte 字节文件
     * @return
     */
    public static FileRecordInfo parseFile(String wjm, byte[] fileByte, Map<String,String> aliasMap, FileInputConfig config){
        List<String> header = new ArrayList<>();
        FileRecordInfo recordInfo=new FileRecordInfo();
        //文件类型
        String wjlx = wjm.substring(wjm.lastIndexOf(".") + 1);
        if ("CSV".equalsIgnoreCase(wjlx)) {
            csvParse(header, fileByte,recordInfo,aliasMap,config);
        } else if ("XLSX".equalsIgnoreCase(wjlx) || "XLS".equalsIgnoreCase(wjlx)) {
            excelParse(wjlx, header, fileByte,recordInfo,aliasMap,config);
        } else {
            throw new IllegalArgumentException("只支持CSV与Excel（xlsx和xls）类型的文件！");
        }
        return recordInfo;
    }

    private static void csvParse(List<String> header, byte[] fileByte,FileRecordInfo recordInfo,Map<String,String> aliasMap,FileInputConfig config) {
        ErrOutputData errOutputData = recordInfo.getErrOutputData();
        int errorRowNumber=-1;
        try (InputStream ins = new ByteArrayInputStream(fileByte);
             InputStreamReader isr = new InputStreamReader(ins, JdbcCharUtil.isUTF8(fileByte)? "UTF-8":"GBK")) {
            CsvReader reader = CsvUtil.getReader();
            CsvData read = reader.read(isr);
            List<CsvRow> rows = read.getRows();
            CsvRow row = rows.get(0);
            if (ObjectUtil.isNull(row)) {
                throw new IllegalArgumentException("该文件没有标题！");
            }
            header.addAll(row.getRawList());
            for (int i = 1; i < rows.size(); i++) {
                List<String> rawList = rows.get(i).getRawList();
                Map<String, Field> data = new HashMap<>();
                try {
                    for (int i1 = 0; i1 < rawList.size(); i1++) {
                        if(aliasMap.containsKey(header.get(i1))){
                            data.put(JdbcCharUtil.getAliasName(aliasMap,header.get(i1)), Field.create(Field.Type.STRING, DateConvertUtil.convertDateStr(rawList.get(i1))));
                        }
                    }
                    if(config.isIncrementalMode()){
                        Field field = data.get(config.getOffsetColumn());
                        if(field!=null && field.getValue()!=null){
                            if(DateConvertUtil.isGreaterThanInitialOffset(config.getInitialOffset(),String.valueOf(field.getValue()))){
                                recordInfo.incrementSuccessCount();
                            }else {
                                data.clear();
                            }
                        }
                    }else {
                        recordInfo.incrementSuccessCount();
                    }
                } catch (Exception exception) {
                    errorRowNumber=i;
                    recordInfo.incrementErrorCount();
                    log.error("当前【{}】行解析异常!",i,exception);
                    throw exception;
                }
                if (ObjectUtil.isNotEmpty(data)) {
                    recordInfo.setSuccessRecord(data);
                    recordInfo.incrementTotalCount();
                }
            }
        } catch (Exception e) {
            errOutputData.setErrorRowOrder(errorRowNumber);
            errOutputData.setType("FILE-CSV");
            errOutputData.setErrorMessage(e.toString());
            errOutputData.setFirstBatchError(true);
            log.error("解析文件异常!",e);
            throw new IllegalArgumentException(e);
        }
    }


    private static void excelParse(String wjlx, List<String> header, byte[] fileByte,FileRecordInfo recordInfo,Map<String,String> aliasMap,FileInputConfig config) {
        ErrOutputData errOutputData = recordInfo.getErrOutputData();
        int errorRowNumber=-1;
        try (InputStream ins = new ByteArrayInputStream(fileByte)) {
            Workbook sheets;
            if ("XLSX".equalsIgnoreCase(wjlx)) {
                sheets = new XSSFWorkbook(ins);
            } else {
                sheets = new HSSFWorkbook(ins);
            }
            int numberOfSheets = sheets.getNumberOfSheets();
            log.info("sheets:{}",numberOfSheets);
            for (int i = 0; i < numberOfSheets; i++) {
                Sheet sheetAt = sheets.getSheetAt(i);
                int physicalNumberOfRows = sheetAt.getPhysicalNumberOfRows();
                //先处理标题行
                if (i == 0) {
                    Row head = sheetAt.getRow(0);
                    if (ObjectUtil.isNull(head)) {
                        throw new IllegalArgumentException("该文件没有标题！");
                    }
                    int headColumns = head.getPhysicalNumberOfCells();
                    for (int i2 = 0; i2 < headColumns; i2++) {
                        Cell cell = head.getCell(i2);
                        header.add(getCellValue(cell));
                    }
                }
                //跳过标题行
                int columns = header.size();
                for (int i1 = 1; i1 < physicalNumberOfRows; i1++) {
                    Map<String, Field> data = new HashedMap<>();
                    Row row = sheetAt.getRow(i1);
                    if (ObjectUtil.isNull(row)) {
                        continue;
                    }
                    try {
                        for (int i2 = 0; i2 < columns; i2++) {
                            if(aliasMap.containsKey(header.get(i2))){
                                Cell cell = row.getCell(i2);
                                data.put(JdbcCharUtil.getAliasName(aliasMap,header.get(i2)), Field.create(Field.Type.STRING, DateConvertUtil.convertDateStr(getCellValue(cell))));
                            }
                        }
                        if(config.isIncrementalMode()){
                            Field field = data.get(config.getOffsetColumn());
                            if(field!=null && field.getValue()!=null){
                                if(DateConvertUtil.isGreaterThanInitialOffset(config.getInitialOffset(),(String)field.getValue())){
                                    recordInfo.incrementSuccessCount();
                                }else {
                                    data.clear();
                                }
                            }
                        }else {
                            recordInfo.incrementSuccessCount();
                        }
                    } catch (Exception exception) {
                        recordInfo.incrementErrorCount();
                        errorRowNumber=i1;
                        log.error("当前【{}】行解析异常!",i1,exception);
                        throw exception;
                    }
                    if (ObjectUtil.isNotEmpty(data)) {
                        recordInfo.setSuccessRecord(data);
                        recordInfo.incrementTotalCount();
                    }
                }
            }
        } catch (Exception e) {
            errOutputData.setErrorRowOrder(errorRowNumber);
            errOutputData.setType("FILE-"+wjlx);
            errOutputData.setErrorMessage(e.toString());
            errOutputData.setFirstBatchError(true);
            throw new IllegalArgumentException(e);
        }
    }

    private static String getCellValue(Cell cell){
        if(cell == null || cell.getCellTypeEnum() == CellType.BLANK){
            return "";
        }
        if(cell.getCellTypeEnum() == CellType.STRING){//字符串
            return cell.getStringCellValue();
        }else if(cell.getCellTypeEnum() == CellType.NUMERIC){//数值
            if (DateUtil.isCellDateFormatted(cell)) {//日期类型
                return JdbcCharUtil.getDateStr(cell.getDateCellValue());
            } else {//数值类型
                String s = Double.toString(cell.getNumericCellValue());
                // 去掉尾巴上的小数点0
                if (Pattern.matches(".*\\.0*", s)) {
                    return s.split("\\.")[0];
                } else {
                    return s;
                }
            }
            //布尔类型
        }else if(cell.getCellTypeEnum() == CellType.BOOLEAN){
            return cell.getBooleanCellValue()? "true" : "false";
        }else{
            return "";
        }
    }
}